這幾篇沒有打算從頭教學golang的interface怎麼使用,網路上的範例和資料隨處可見,多多參考不同的見解,就可以對interface有相當的認識,筆者就不特地獻醜了。
筆者寫了好一段時間的golang,也花上許多時間研究interface相關的文章介紹,理解起來還是模模糊糊的,直到在研究結構設計的時候,獲得靈感和啟發,因此也想用講解結構設計的方式,跟大家分享interface的應用方式。
請跟我看一下這段source code
這是golang的DB連線struct,其中connector是屬於driver.Connector型態。
而driver.Connector是interface。
ok,到這邊,我們簡單來看,就把它當作有個叫做DB的『struct』 型態,裡面包含了某個變數是『interface』的型態。
struct 有個型態是 interface 的變數。
我們來回顧struct的特徵,strcut基本上會擁有兩種專屬於它的東西,一是它擁有的變數,二是它擁有的method。
假設是struct包著struct,那麼外面的struct擁有自己的變數和method,內部的struct也擁有自己的變數和method。
那interface擁有什麼呢?只能擁有method。
重點來了,這就是思考方式的分歧點。
先拉遠講個題外話,有一次筆者在找方法取得拿到goroutine的ID,但是找了一陣子,發現大家都是說沒有這樣的東西,也不能有這個東西。
因為那時蠻白爛地想要控制goroutine的使用狀況,以及插手裡面的工作。
意外的收穫,是有找到資料講解,說goroutine如果有讓外部取得可以做識別的參數存在,那麼會失去匿名性,就不能一視同仁的處理goroutine們的工作。
這道理可以應用上struct與interface兩者的處境。
struct 擁有自己的變數,這點就是很強烈的識別因子,簡單舉例int和string,兩者是完全不同的型態,你在某種情況下需要存int型態的變數,另一種情況下需要string,那麼不好意思,兩者無法兼之,除非你把它設計成interface{}的型態,而且進行後續處理。
interface 的話只剩下method,method在定義出method name、input、output後,剩下method裡面怎麼寫,隨便你開心。
如它的Connector
type Connector interface {
// Connect returns a connection to the database...
Connect(context.Context) (Conn, error)
// Driver returns the underlying Driver of the Connector ...
Driver() Driver
}
重頭戲來了,Zero Values 的概念會是理解interface很關鍵的要點。
先來想想,struct的zero value是什麼?
答案是:內部所有變數都是zero value的struct。
如
type SuperFish struct {
id int
name string
size float64
}
var superfish SuperFish
這個superfish,zero value內容是擁有id:0,name:"",size:0.0 的struct。
那interface的zero value是什麼?
答案是:nil。
最後一點,function 的zero value 會是什麼?
答案也是:nil。
所以interface的zero value會是nil也是理所當然,因為它底下的method初始值都是nil。
請思考一下,這樣的zero value會有什麼影響?為什麼DB裡面的Connector會選擇用一個interface的型態,而不是選擇struct,struct也是可以使用他的method。